package com.share.admin.web;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.share.admin.config.security.LoginUser;
import com.share.admin.config.security.SecurityContext;
import com.share.admin.constant.SysConstant;
import com.share.admin.model.db.Dictionary;
import com.share.admin.model.db.User;
import com.share.admin.model.vo.LoginReq;
import com.share.admin.model.vo.MenuVo;
import com.share.admin.model.vo.UserAddOrUpdateReq;
import com.share.admin.model.vo.UserPageReq;
import com.share.admin.service.IDictionaryService;
import com.share.admin.service.IMenuService;
import com.share.admin.service.IUserService;
import com.share.common.common.LoginInfo;
import com.share.common.common.Page;
import com.share.common.common.Result;
import com.share.common.utils.UUIDUtil;
import com.share.config.redis.RedisTokenManager;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表  前端控制器
 * </p>
 *
 * @author author
 * @since 2022-09-22
 */
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private IUserService iUserService;
    @Autowired
    private IDictionaryService iDictionaryService;
    @Autowired
    private IMenuService iMenuService;
    @Autowired
    private RedisTokenManager tokenManager;

    @Autowired
    private AuthenticationManager authenticationManager;

    @PostConstruct
    public void initDefault() {
        log.info("----正在初始化swagger登录用户---");
        try {
            User user = iUserService.getByAccount(SysConstant.SWAGGER_USER_ACCOUNT);
            user.setPassword(null);
            LoginUser login = new LoginUser(user, null);
            tokenManager.setUserInfo(genToken(user.getAccount()), JSON.toJSONString(login));
        } catch (Exception e) {
            log.info("swagger用户初始化异常", e);
        }
    }

    /**
     * 获取用户列表
     */
    @RequestMapping("/list")
    public Result list() {
        Set<User> set = null;
        if (SecurityContext.isAdmin()) {
            set = iUserService.listAll();
        } else {
            Long userId = SecurityContext.getUserId();
            set = iUserService.listByUserId(userId);
        }
        return Result.success(set);
    }

    /**
     * 在SpringSecurity中，认证或授权出现异常会被ExceptionTranslationFilter捕获到，他会去判断是认证失败还是授权失败出现异常。
     * 如果是认证过程中出现异常，那么异常会被封装成AuthenticationException然后调用AuthenticationEntryPoint的方法对异常进行处理。
     * 如果是授权过程中出现异常，会被封装成AccessDeniedException然后调用AccessDeniedHandler的方法对异常进行处理。
     */

    @ApiOperation("登录")
    @RequestMapping("/login")
    public Result login(LoginReq req) {
        if (StringUtils.isEmpty(req.getAccount()) || StringUtils.isEmpty(req.getPassword())) {
            return Result.failure("参数异常");
        }

        //使用Authentication的实现类
        Authentication authentication = new UsernamePasswordAuthenticationToken(req.getAccount(), req.getPassword());

        //手动调用方法去认证 他会自动调用UserDetailsService并进行比对
        Authentication authenticate = authenticationManager.authenticate(authentication);
        if (Objects.isNull(authenticate)) { //说明输入错误
            return Result.failure("用户名或密码错误");
        }

        //拿到用户信息 然后生成jwt返回给前端，并且将用户的信息存入redis
        LoginUser login = (LoginUser) authenticate.getPrincipal(); // 这个其实就是UserDetails 也就是LoginUser

        //组装返回给前端的对象
        LoginInfo loginInfo = new LoginInfo();
        User user = login.getUser();
        String token = genToken(user.getAccount());//生成token
        loginInfo.setToken(token);
        loginInfo.setAccount(user.getAccount());
        loginInfo.setUserId(user.getId());
        loginInfo.setNickName(user.getNickName());
        loginInfo.setPermissions(login.getPermissions());

        /*那用户信息存入redis*/
        String loginStr = JSON.toJSONString(login);
        log.info("用户信息存入redis,token={},loginUser={}", token, loginStr);
        boolean saveFlag = tokenManager.setUserInfo(token, loginStr);
        if (!saveFlag) {
            return Result.failure("存储到redis系统异常");
        }
        JSONObject reJson = JSON.parseObject(JSON.toJSONString(loginInfo));

        //菜单信息加载
        Set<MenuVo> menusVo = null;
        if (SysConstant.ADMIN.equals(user.getAccount())) {
            menusVo = iMenuService.treeAll();
        } else {
            menusVo = iMenuService.treeByUserId(user.getId());
        }
        reJson.put("menus", menusVo);

        //字典数据
        Map<String, List<Dictionary>> allGCode = iDictionaryService.getAllGCode();
        reJson.put("dictionary", allGCode);

        log.info("返回给页面的登录信息={}", JSON.toJSON(reJson));
        return Result.success(reJson);
    }

    @ApiOperation("退出")
    @RequestMapping("/logout")
    public Result logout(HttpServletRequest request) {
        boolean bool = tokenManager.delUserInfo(request);
        return Result.bool(bool);
    }


    //生成token
    private String genToken(String account) {
        String token = null;
        if (SysConstant.SWAGGER_USER_ACCOUNT.equals(account)) {
            token = SysConstant.SWAGGER_USER_TOKEN;
        } else {
            token = UUIDUtil.genUUId();
        }
        return token;
    }

    @ApiOperation("用户绑定或者移除角色")
    @RequestMapping(value = "/bindRoles")
    public Result bindOrRemoveRoles(Boolean isBind, String userId, String roleIds) {
        if (isBind == null || StringUtils.isBlank(userId)) {
            return Result.failure("isBind,userId参数异常!");
        }
        List<String> list = null;
        if (StringUtils.isNotEmpty(roleIds)) {
            list = Arrays.stream(roleIds.split(",")).collect(Collectors.toList());
        }

        if (isBind && CollectionUtils.isEmpty(list)) {
            return Result.failure("roleIds值异常,没有可绑定的角色!");
        }
        return Result.success(iUserService.bindOrRemoveRoles(isBind, userId, list));
    }

    @ApiOperation("分页查询")
    @RequestMapping(value = "/pageList")
    public Result resultPageList(UserPageReq req) {
        Page page = iUserService.pageList(req);
        return Result.success(page);
    }

    @ApiOperation("新增")
    @RequestMapping("/add")
    public Result add(UserAddOrUpdateReq req) {
        User record = new User();
        BeanUtils.copyProperties(req, record);
        return Result.bool(iUserService.save(record));
    }

    @ApiOperation("修改")
    @RequestMapping("/update")
    public Result update(UserAddOrUpdateReq req) {
        if (req.getId() == null) {
            return Result.failure("参数异常!");
        }
        User record = new User();
        BeanUtils.copyProperties(req, record);
        return Result.bool(iUserService.updateById(record));
    }

    @ApiOperation("删除")
    @RequestMapping("/delete")
    public Result delete(Integer id) {
        return Result.bool(iUserService.removeById(id));
    }

}
